package com.cwx.mychat.filter;


import com.cwx.mychat.entity.constant.CodeConstant;
import com.cwx.mychat.entity.dto.TokenUserInfoDto;
import com.cwx.mychat.entity.enums.ExceptionBizCodeEnum;
import com.cwx.mychat.entity.po.UserInfo;
import com.cwx.mychat.entity.vo.UserInfoVO;
import com.cwx.mychat.mappers.UserInfoMapper;
import com.cwx.mychat.utils.R;
import com.cwx.mychat.utils.common.CommonUtil;
import com.cwx.mychat.utils.redis.RedisComponent;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Component
@WebFilter(urlPatterns = "/*",filterName = "AuthenticationTokenFilter")
@Order(-1)//指定过滤器的执行顺序,值越小越靠先执行
public class AuthenticationTokenFilter extends OncePerRequestFilter {

    @Autowired
    private RedisComponent redisComponent;

    @Autowired
    private UserInfoMapper userInfoMapper;


    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest,
                                    @NotNull HttpServletResponse httpServletResponse,
                                    @NotNull FilterChain filterChain) throws ServletException, IOException {
        //查询心跳
        String userId;
        String token = httpServletRequest.getHeader("Authorization");
        log.info("获取token {}", token);
        //token不存在，直接放行
        if(!StringUtils.hasText(token)){
            try{
                //todo 从本地获取账号，如果获取直接登录， 这里暂时写成获取心跳，后续在更改
                token = httpServletRequest.getParameter("token");
                //判断是否是同一个账号
                String a = httpServletRequest.getParameter("a");
                if (a != null && Objects.equals(a, "1")) {
                    //不同账号
                    filterChain.doFilter(httpServletRequest, httpServletResponse);
                    return;
                }
                //token不存在，直接放行
                if(!StringUtils.hasText(token)){
                    filterChain.doFilter(httpServletRequest, httpServletResponse);
                    return;
                }
                //校验token
                userId = CommonUtil.checkToken(token);
            }catch (Exception e){
                log.info("jwt过期，重新登录", e);
                filterChain.doFilter(httpServletRequest, httpServletResponse);
                return;
            }
            if(userId != null){
                //账号正在使用
                //todo 先判断是否在本机,如果在本机则直接登录，不在本机则不登录
                //获取用户信息并校验
                try{
                    checkUser(userId);
                }catch (Exception e){
                    log.info("用户未登录， 放行重新登录");
                    filterChain.doFilter(httpServletRequest, httpServletResponse);
                    return;
                }
                //将用户信息返回给前端
                UserInfo userInfo = userInfoMapper.selectById(userId);
                UserInfoVO userInfoVO = new UserInfoVO();
                BeanUtils.copyProperties(userInfo, userInfoVO);
                userInfoVO.setToken(token);
                Map<String, Object> map = new HashMap<>();
                map.put("code", 1);
                map.put("msg", "成功");
                map.put(CodeConstant.RESULT_MSG, userInfoVO);
                CommonUtil.responseOutWithJson(httpServletResponse, map);
                return;
            }
            filterChain.doFilter(httpServletRequest, httpServletResponse);
            return;
        }
        //检查Token是否过期
        userId = CommonUtil.checkToken(token);
        //根据UserId获取用户信息
        checkUser(userId);
        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }

    private void checkUser(String userId){
        TokenUserInfoDto dto = redisComponent.getTokenUserInfoDto(userId);
        if(Objects.isNull(dto)){
            throw new RuntimeException(ExceptionBizCodeEnum.ACCOUNT_NOT_LOGIN.getMsg());
        }
        if(dto.getAdmin()){
            //无权限
            throw new RuntimeException(ExceptionBizCodeEnum.ACCOUNT_NO_PERMISSION.getMsg());
        }
        //将用户信息存放在SecurityContextHolder.getContext()，后面的过滤器就可以获得用户信息实现无状态验证
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken=new UsernamePasswordAuthenticationToken(dto,null,null);
        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
    }
}
